/*
 * SendMail.java
 * 
 * This file is part of Netuno Psamata.
 * 
 * CajuScript is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3, or (at your option) 
 * any later version.
 * 
 * CajuScript is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with CajuScript.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.netuno.psamata.mail;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.security.Security;
import java.util.Properties;
import javax.mail.Session;
import javax.mail.Message;
import javax.mail.Transport;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.InternetAddress;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import java.util.Date;
import javax.activation.FileDataSource;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;

/**
 * Send Mail.
 * @author eduveks
 */
public class SendMail {
    private String server = "";
    private int port = 0;
    private String protocol = "";
    private boolean TLS = false;
    private boolean SSL = false;
    private String username = "";
    private String password = "";
    private String socketFactoryClass = "";
    private int socketFactoryPort = 0;
    private boolean socketFactoryFallback = false;
    private boolean quitWait = false;
    private Properties properties = new Properties();
    private String from = "";
    private String to = "";
    private String cc = "";
    private String bcc = "";
    private String subject = "";
    private String text = "";
    private boolean html = false;
    private Date sentDate = new Date();
    private File[] attachments = new File[0];

    /**
     * Send Mail.
     */
    public SendMail() {
        setProtocol("smtp");
        setServer("localhost");
        getProperties().put("mail.smtps.ssl.trust", "*");
        getProperties().put("mail.smtp.ssl.trust", "*");
    }
    /**
     * Send Mail.
     */
    public final void sendMail() {
        try {
            Session session = null;
            if (getUsername().length() > 0) {
                session = Session.getDefaultInstance(getProperties(), new javax.mail.Authenticator() {
                    @Override
                    protected PasswordAuthentication getPasswordAuthentication() {
                        return new PasswordAuthentication(getUsername(), getPassword());
                    }
                });
            } else {
                session = Session.getInstance(getProperties(), null);
            }
            MimeMessage msg = new MimeMessage(session);
            if (isHtml()) {
                msg.setHeader("X-Mailer", "sendhtml");
            }
            if (!getFrom().equals("")) {
                msg.setFrom(new InternetAddress(getFrom()));
            }
            if (!getTo().equals("")) {
                msg.addRecipients(Message.RecipientType.TO,
                getTo());
            }
            if (!getCc().equals("")) {
                msg.addRecipients(Message.RecipientType.CC,
                getCc());
            }
            if (!getBcc().equals("")) {
                msg.addRecipients(Message.RecipientType.BCC,
                getBcc());
            }
            msg.setSentDate(getSentDate());
            msg.setSubject(subject);
            DataHandler dataHandler = new DataHandler(new DataSource() {
                public InputStream getInputStream() throws IOException {
                    return new ByteArrayInputStream(getText().getBytes());
                }
                public OutputStream getOutputStream() throws IOException {
                    throw new UnsupportedOperationException("Not supported.");
                }
                public String getContentType() {
                    return isHtml() ? "text/html" : "text/plain";
                }
                public String getName() {
                    return "";
                }
            });
            if (attachments.length > 0) {
                MimeBodyPart body = new MimeBodyPart();
                body.setDataHandler(dataHandler);
                Multipart multipart = new MimeMultipart();
                multipart.addBodyPart(body);
                for (File attachment : attachments) {
                    MimeBodyPart attachMent = new MimeBodyPart();
                    FileDataSource dataSource = new FileDataSource(attachment);
                    attachMent.setDataHandler(new DataHandler(dataSource));
                    attachMent.setFileName(attachment.getName());
                    attachMent.setDisposition(MimeBodyPart.ATTACHMENT);
                    multipart.addBodyPart(attachMent);
                }
                msg.setContent(multipart);
            } else {
                msg.setDataHandler(dataHandler);
            }
            Transport.send(msg);
        } catch (Exception e) {
            throw new Error(e);
        }
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    /**
     * Get From.
     * @return From
     */
    public final String getFrom() {
        return from;
    }

    /**
     * Set From.
     * @param from From
     */
    public final void setFrom(final String from) {
        this.from = from;
    }

    /**
     * Is Html Content.
     * @return Is Html Content
     */
    public final boolean isHtml() {
        return html;
    }

    /**
     * Set Html.
     * @param html Is Html
     */
    public final void setHtml(final boolean html) {
        this.html = html;
    }

    /**
     * Get Server. The default value is "localhost". Value to <i>mail.host</i>.
     * @return Server
     */
    public final String getServer() {
        return server;
    }

    /**
     * Set Server. The default value is "localhost". Value to <i>mail.host</i>.
     * @param server Server
     */
    public final void setServer(final String server) {
        this.server = server;
        properties.put("mail.host", getServer());
    }

    /**
     * Set Server Port. Value to <i>mail.smtp.port</i>.
     * @return Port number
     */
    public int getPort() {
        return port;
    }

    /**
     * Get Server Port. Value to <i>mail.smtp.port</i>.
     * @param port Port number
     */
    public void setPort(int port) {
        this.port = port;
        properties.put("mail.smtp.port", Integer.toString(getPort()));
    }

    /**
     * Get Protocol. The default value is "smtp". Value to <i>mail.transport.protocol</i>.
     * @return Protocol
     */
    public String getProtocol() {
        return protocol;
    }

    /**
     * Set Protocol. The default value is "smtp". Value to <i>mail.transport.protocol</i>.
     * @param protocol Protocol
     */
    public void setProtocol(String protocol) {
        this.protocol = protocol;
        properties.setProperty("mail.transport.protocol", getProtocol());
    }

    /**
     * Get if TLS mode was activated.
     * @return
     */
    public boolean isTLS() {
        return TLS;
    }

    /**
     * Set if is to active TLS support. Default is false, and if is true is
     * loaded automatically the
     * <i>mail.smtp.starttls.enable=true</i>
     * and
     * <i>mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory</i>
     * and also
     * <i>Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());</i>
     * @param TLS
     */
    public void setTLS(boolean TLS) {
        this.TLS = TLS;
        if (isTLS()) {
        	properties.put("mail.smtp.starttls.enable","true");
        } else {
        	properties.put("mail.smtp.starttls.enable","false");
        }
    }
    
    /**
     * Get if SSL mode was activated.
     * @return
     */
    public boolean isSSL() {
        return SSL;
    }

    /**
     * Set if is to active SSL support. Default is false, and if is true is
     * loaded automatically the
     * <i>mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory</i>
     * and also
     * <i>Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());</i>
     * @param SSL
     */
    public void setSSL(boolean SSL) {
        this.SSL = SSL;
        if (isSSL()) {
            Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
            setSocketFactoryClass("javax.net.ssl.SSLSocketFactory");
        }
        if (getSocketFactoryClass().length() > 0) {

        }
    }

    /**
     * Set User Name.
     * @return User Name
     */
    public String getUsername() {
        return username;
    }

    /**
     * Set User Name. Is set automatically the <i>mail.smtp.auth</i> to
     * <i>true</i> (if the user name is not empty) or
     * <i>false</i> (if the user name is empty).
     * @param username User Name
     */
    public void setUsername(String username) {
        this.username = username;
        if (getUsername().length() > 0) {
            properties.put("mail.smtp.auth", "true");
        } else {
            properties.put("mail.smtp.auth", "false");
        }
    }

    /**
     * Get Password.
     * @return Password
     */
    public String getPassword() {
        return password;
    }

    /**
     * Set Password.
     * @param password Password
     */
    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * Get Socket Factory Class. Value to <i>mail.smtp.socketFactory.class</i>.
     * @return Socket Factory Class
     */
    public String getSocketFactoryClass() {
        return socketFactoryClass;
    }

    /**
     * Set Socket Factory Class. Value to <i>mail.smtp.socketFactory.class</i>.
     * @param socketFactoryClass Socket Factory Class
     */
    public void setSocketFactoryClass(String socketFactoryClass) {
        this.socketFactoryClass = socketFactoryClass;
        properties.put("mail.smtp.socketFactory.class", getSocketFactoryClass());
    }

    /**
     * Is Socket Factory Fallback? Value to <i>mail.smtp.socketFactory.fallback</i>.
     * @return Socket Factory Fallback
     */
    public boolean isSocketFactoryFallback() {
        return socketFactoryFallback;
    }

    /**
     * Set Socket Factory Fallback. Value to <i>mail.smtp.socketFactory.fallback</i>.
     * @param socketFactoryFallback Socket Factory Fallback
     */
    public void setSocketFactoryFallback(boolean socketFactoryFallback) {
        this.socketFactoryFallback = socketFactoryFallback;
        if (isSocketFactoryFallback()) {
            properties.put("mail.smtp.socketFactory.fallback", "true");
        } else {
            properties.put("mail.smtp.socketFactory.fallback", "false");
        }
    }

    /**
     * Get Socket Factory Port. Value to <i>mail.smtp.socketFactory.port</i>.
     * @return Socket Factory Port
     */
    public int getSocketFactoryPort() {
        return socketFactoryPort;
    }

    /**
     * Set Socket Factory Port. Value to <i>mail.smtp.socketFactory.port</i>.
     * @param socketFactoryPort Socket Factory Port
     */
    public void setSocketFactoryPort(int socketFactoryPort) {
        this.socketFactoryPort = socketFactoryPort;
        properties.put("mail.smtp.socketFactory.port", Integer.toString(getSocketFactoryPort()));
    }

    /**
     * Is Quit Wait? Value to <i>mail.smtp.quitwait</i>.
     * @return Quit Wait
     */
    public boolean isQuitWait() {
        return quitWait;
    }

    /**
     * Set Quit Wait. Value to <i>mail.smtp.quitwait</i>.
     * @param quitWait Quit Wait
     */
    public void setQuitWait(boolean quitWait) {
        this.quitWait = quitWait;
        if (isQuitWait()) {
            properties.put("mail.smtp.quitwait", "true");
        } else {
            properties.put("mail.smtp.quitwait", "false");
        }
    }

    public File[] getAttachments() {
        return attachments;
    }

    public void setAttachments(File... attachments) {
        this.attachments = attachments;
    }

    /**
     * Get Subject.
     * @return Subject
     */
    public final String getSubject() {
        return subject;
    }

    /**
     * Set Subject.
     * @param subject Subject
     */
    public final void setSubject(final String subject) {
        this.subject = subject;
    }

    /**
     * Get Text.
     * @return Text
     */
    public final String getText() {
        return text;
    }

    /**
     * Set Text.
     * @param text Text
     */
    public final void setText(final String text) {
        this.text = text;
    }

    /**
     * Get To.
     * @return To
     */
    public final String getTo() {
        return to;
    }

    /**
     * Set To.
     * @param to To
     */
    public final void setTo(final String to) {
        this.to = to;
    }
    
    /**
     * Get Cc.
     * @return Cc
     */
    public String getCc() {
        return cc;
    }

    /**
     * Set Cc.
     * @param cc Cc
     */
    public void setCc(String cc) {
        this.cc = cc;
    }

    /**
     * Get Bcc.
     * @return Bcc
     */
    public String getBcc() {
        return bcc;
    }

    /**
     * Set Bcc.
     * @param bcc Bcc
     */
    public void setBcc(String bcc) {
        this.bcc = bcc;
    }

    /**
     * Get sent date.
     * @return Sent date
     */
    public Date getSentDate() {
        return sentDate;
    }

    /**
     * Set sent date.
     * @param sentDate Sent date
     */
    public void setSentDate(Date sentDate) {
        this.sentDate = sentDate;
    }
}
/**
* Byte Array Data Source.
*/
class ByteArrayDataSource implements DataSource {
    /**
     * Data.
     */
    private byte[] data;
    /**
     * Type.
     */
    private String type;
    /**
     * Byte Array Data Source.
     * @param is Input Stream
     * @param t Type
     */
    public ByteArrayDataSource(final InputStream is, final String t) {
        type = t;
        try {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            int ch;
            while ((ch = is.read()) != -1) {
                os.write(ch);
            }
            data = os.toByteArray();
        } catch (IOException ioex) {
            return;
        }
    }
    /**
     * Byte Array Data Source.
     * @param bytes Data Bytes
     * @param t Type
     */
    public ByteArrayDataSource(final byte[] bytes, final String t) {
        data = bytes;
        type = t;
    }
    /**
     * Byte Array Data Source.
     * @param str Data String
     * @param t Type
     */
    public ByteArrayDataSource(final String str, final String t) {
        data = str.getBytes();
        type = t;
    }
    /**
     * Get Input Stream.
     * @return Input Stream
     * @throws IOException Input Exception
     */
    public final InputStream getInputStream() throws IOException {
        if (data == null) {
            throw new IOException("no data");
        }
        return new ByteArrayInputStream(data);
    }
    /**
     * Get Output Stream.
     * @return Output Stream
     * @throws IOException Output Exception
     */
    public final OutputStream getOutputStream() throws IOException {
        throw new IOException("cannot do this");
    }
    /**
     * Get Content Type.
     * @return Content Type
     */
    public final String getContentType() {
        return type;
    }
    /**
     * Get Name.
     * @return Name
     */
    public final String getName() {
        return "dummy";
    }
}
